

package scalaSci.EJML

import java.util._
import org.ejml.UtilEjml
import org.ejml.alg.dense.decomposition.DecompositionFactory
import org.ejml.alg.dense.decomposition.EigenDecomposition
import org.ejml.alg.dense.decomposition.SingularMatrixException
import org.ejml.alg.dense.decomposition.SingularValueDecomposition
import org.ejml.ops._
import org.ejml.simple.SimpleMatrix
import org.ejml.data.DenseMatrix64F

import scala._
import scala.collection.generic._

// this class provides Matrix operations, by wrapping the Efficient Java Matrix Library
class Mat(smi: SimpleMatrix ) {    
    var  sm = smi   // keep the reference to the SimpleMatrix
// getters for size
    def  Nrows = smi.numRows()
    def  Ncols = smi.numCols()
    def size = {  (Nrows, Ncols) }  // the size of the Matrix
    def length =  { Nrows }

def this(N: Int, M: Int) = {
     this(new SimpleMatrix(N, M))
   } 

def this(values: Array[Array[Double]]) = {
  this(new SimpleMatrix(values))
}

def getv = {
    sm.getMatrix.data
  }

// apply the function f to all the elements of the Matrix and return the results with a new Matrix
 def  map( f: (Double => Double)): Mat = {
   var mres = new Mat(Nrows, Ncols)
   
    for (r<-0 until Nrows)
      for (c<-0 until Ncols) 
       mres(r, c) = f(this(r, c) )
   
   mres
 }

// print the Matrix contents
def print = { sm.print }

// prints the matrix out with the specified precision
def print(numChar: Int, precision: Int) = { sm.print(numChar, precision) }

// Prints the matrix to standard out given a printf() style floating point format, e.g. print("%f").
def print( format: String) = { sm.print(format) }

// short print method
def p( format: String) = { sm.print(format) }

def p = print

// Extracts a row or column from this matrix and returns it as a row matrix of the appropriate length.
//    @param extractRow is a row vector begin extracted.
//    @param element The row or column the vector is contained in.
//    @return Extracted vector.
// used to implement the apply()
def extractVector(extractRow: Boolean, element: Int) =
   {
 new Mat( sm.extractVector(extractRow, element))
 }
   
  //  Creates a new identity matrix with the specified size.
  //     @param width The width and height of the matrix.
  //     @return An identity matrix.
 def  identity(width: Int ) = {
   new Mat( SimpleMatrix.identity(width))
}


def isVector =  sm.isVector   //  a 1-D Matrix

def dot(that: Mat) =  {
    sm.dot(that.sm)
}

  
//   Returns a reference to the matrix that it uses internally.  This is useful
//    when an operation is needed that is not provided by this class.
//      @return Reference to the internal DenseMatrix64F.
def getMatrix = {
  sm.getMatrix
  }

//  Returns the transpose of this matrix.
def  transpose = {
  var  ret = new SimpleMatrix(sm.getMatrix.numCols, sm.getMatrix.numRows)
  CommonOps.transpose(sm.getMatrix, ret.getMatrix)

 new Mat( ret )
  }


// postfix transpose operator
def ~() =  {
  var  ret = new SimpleMatrix(sm.getMatrix.numCols, sm.getMatrix.numRows)
  CommonOps.transpose(sm.getMatrix, ret.getMatrix)

 new Mat( ret )
} 


//   Performs a matrix multiplication operation.
//        c = a * b 
//   where c is the returned matrix, a is this matrix, and b is the passed in matrix.
//       @param b A matrix that is n by bn. Not modified.
//       @return The results of this operation.
def  * (that: Mat): Mat = {
    var  rN = this.Nrows;   var rM = this.Ncols;
    var  sN = that.Nrows;  var sM = that.Ncols;
   
    var ret = new SimpleMatrix(sm.getMatrix.numRows, that.sm.getMatrix.numCols)
    CommonOps.mult(sm.getMatrix, that.sm.getMatrix, ret.getMatrix)

    new Mat(ret)
 }


//  Multiplies each element in this matrix by the specified value.
//    @param scalef: The multiplication factor.
//   @return The scaled matrix.
def  * ( scalef: Double) = {
      new Mat( sm.scale( scalef) )
 }




// Extracts the diagonal from this matrix and returns them inside a column vector.
def  extractDiag = {
  new Mat(sm.extractDiag())
}

//  Checks to see if matrix 'a' is the same as this matrix within the specified  tolerance.
//    @param a The matrix it is being compared against.
//    @param tol How similar they must be to be equals.
//    @return If they are equal within tolerance of each other.
def  isIdentical( a: Mat, tol: Double) =  {
  sm.isIdentical( a.sm, tol )
}

// Checks to see if any of the elements in this matrix are either NaN or infinite.
//   @return True of an element is NaN or infinite.  False otherwise.
def  hasUncountable = {
        sm.hasUncountable
   }
          

// perform Matrix addition with a number
def +( that: Double) = { 
  var rN = this.Nrows;   var rM = this.Ncols;  // receiver's dimensions
  var i=0; var j=0;
  var smSub = new org.ejml.simple.SimpleMatrix(rN, rM)   // new SimpleMatrix to perform the subtraction
  while (i<rN) {
       j=0
      while (j<rM) {
        smSub.set(i, j, sm.get(i, j)+that)
        j += 1
         }
     i += 1
   }
 
  new Mat(smSub)
}


// perform Matrix subtraction with a number
def -( that: Double) = {
  var rN = this.Nrows;   var rM = this.Ncols;  // receiver's dimensions
  var i=0; var j=0;
  var smSub = new org.ejml.simple.SimpleMatrix(rN, rM)   // new SimpleMatrix to perform the subtraction
  while (i<rN) {
       j=0
      while (j<rM) {
        smSub.set(i, j, sm.get(i, j)-that)
        j += 1
         }
     i += 1
   }
 
  new Mat(smSub)
}

    

// perform Matrix addition
def +( that: Mat) = {
  new Mat( sm.plus(that.sm))
  }

// perform Matrix subtraction
def - ( that: Mat ) = {
  new Mat( sm.minus(that.sm))
}

//   Divides each element in this matrix by the specified value.
//     * @param value Divisor.
//     * @return Matrix with its elements divided by the specified value.
def  / ( value: Double ) = {
    new Mat(sm.divide(value))
}


//  Copy matrix B into this matrix at location (insertRow, insertCol).
//   @param insertRow First row the matrix is to be inserted into.
//   @param insertCol First column the matrix is to be inserted into.
//   @param B The matrix that is being inserted.
def insertIntoThis(insertRow: Int, insertCol: Int, B: Mat)  = {
        CommonOps.insert(B.sm.getMatrix(), sm.getMatrix, insertRow,insertCol);
    }


//   Solves for X in the following equation:
//      x = a^{-1}  b
//   where 'a' is this matrix and 'b' is an n by p matrix.
//   If the system could not be solved then SingularMatrixException is thrown.  Even
//   if no exception is thrown 'a' could still be singular or nearly singular.
//      @param b n by p matrix. Not modified.
//      @return The solution for 'x' that is n by p.
def  solve(b: Mat )  =
    {
        new Mat(sm.solve(b.sm)) 
    }



//  Sets the elements in this matrix to be equal to the elements in the passed in matrix.
//   Both matrix must have the same dimension.
//      @param a The matrix whose value this matrix is being set to.
def  set( a: Mat  ) = {
        sm.getMatrix.set(a.sm.getMatrix())
    }



//  Sets all the elements in this matrix equal to the specified value.
def set( value: Double ) = {
        CommonOps.set(sm.getMatrix,value)
    }

//  Sets all the elements in the matrix equal to zero.
def  zero = {
        sm.getMatrix.zero
    }

//  Computes the Frobenius normal of the matrix:
def  normF = {
      NormOps.normF(sm.getMatrix)
    }

// The condition p = 2 number of a matrix is used to measure the sensitivity of the linear
// system  Ax=b.  A value near one indicates that it is a well conditioned matrix.
//     @return The condition number.
def  conditionP2 = {
      NormOps.conditionP2(sm.getMatrix)
    }

// Computes the determinant of the matrix.
def det = {
        sm.determinant
    }


//  Computes the trace of the matrix.
def  trace = {
     sm.trace
    }

//  Reshapes the matrix to the specified number of rows and columns.  
//      @param numRows The new number of rows in the matrix.
//      @param numCols The new number of columns in the matrix.
def  reshape( numRows: Int, numCols: Int ) = {
        sm.getMatrix.reshape(numRows, numCols, true)
    }

def update( row: Int, col: Int, value: Double) = {
    sm.set(row, col, value)
    } 

def apply( row: Int, col: Int) = {
    sm.get( row, col )
   }

def apply( startRow: Int, stopRow: Int, startCol:Int ,stopCol: Int): Mat = {
  if (startRow < stopRow && startCol < stopCol) 
     new Mat(sm.extractMatrix( startRow, stopRow, startCol, stopCol))
else {
   var incR = if (startRow > stopRow) -1 else 1
   var incC = if (startCol > stopCol) -1 else 1
   apply( startRow, incR, stopRow, startCol, incC, stopCol)
   }
}

// i.e. A( 8) for the 8th row
def apply(rowExtract: Int ) = {
   sm.extractVector(true, rowExtract)
 }

// i.e. A(':', 8) for the 8th row
def apply(ch: Char, rowExtract: Int ) = {
   sm.extractVector(true, rowExtract)
 }

// i.e. A(8, ':') for the 8th col
def apply(colExtract: Int, ch: Char ) = {
   sm.extractVector(false, colExtract)
 }

 


// extracts a submatrix specifying rows only, take all columns, e.g. m(2, 3, ':') corresponds to Matlab's m(2:3, :)'
// m(low:high,:) is implemented with m(low, high, dummyChar). if low>high then rows are returned in reverse
 def apply(rowL: Int, rowH: Int, allColsChar: Char): Mat = {
   var rowStart = rowL; var rowEnd=rowH;
   var colStart = 0;     var colEnd =  Ncols-1;   // all columns
   var colNum = Ncols
   var colInc = 1

    if (rowEnd == -1) { rowEnd = Nrows-1 }  // if -1 is specified take all the rows
    
if (rowStart <= rowEnd) {   // positive increment
    var rowInc = 1
    var rowNum = rowEnd-rowStart+1
    var subMatr = new Mat(rowNum, colNum)   // create a Mat to keep the extracted range
      // fill the created matrix with values
    var crow = rowStart  // indexes current row
    var ccol = colStart
    var rowIdx =0; var colIdx = 0  // indexes at the new Matrix
    while  ( crow <= rowEnd )   {
          ccol = colStart;  colIdx = 0
          while  (ccol <= colEnd )   { 
                subMatr.sm.set(rowIdx, colIdx, sm.get(crow, ccol))
                colIdx += 1
                ccol += colInc
               }
            rowIdx += 1
            crow += rowInc
       } // crow <= rowEnd
subMatr   // return the submatrix

} // rowStart <= rowEnd
else { // rowStart > rowEnd
    var rowInc = -1
    var rowNum = rowStart-rowEnd+1
    var subMatr = new Mat(rowNum, colNum)   // create a Mat to keep the extracted range
      // fill the created matrix with values
    var crow = rowStart  // indexes current row at the source matrix
    var ccol = colStart
    var rowIdx =0; var colIdx = 0  // indexes at the new Mat
    while  ( crow >= rowEnd )   {
          ccol = colStart;  colIdx = 0
          while  (ccol <= colEnd)   {
                subMatr.sm.set(rowIdx, colIdx, sm.get(crow, ccol))
                colIdx += 1
                ccol += colInc
               }
            rowIdx += 1
            crow += rowInc
       }

subMatr   // return the submatrix

} // rowStart > rowEnd

}

// extracts a submatrix specifying rows only, take all columns, e.g. m(2, 4, 12, ':') corresponds to Matlab's m(2:4:12, :)'
def apply(rowL: Int, rowInc: Int, rowH: Int, allColsChar: Char): Mat = {
    var rowStart = rowL;     var rowEnd =  rowH;
    var colStart = 0;  var colEnd = Ncols-1;   // all columns
    var colNum = Ncols
    var colInc = 1

    if (rowEnd == -1) { rowEnd = Nrows-1 }  // if -1 is specified take all the rows
    
  if (rowInc > 0) { // positive increment
    var rowNum = Math.floor( (rowEnd-rowStart) / rowInc).asInstanceOf[Int]+1
    var colStart = 0;     var colEnd =  Ncols-1   // all columns
    var subMatr = new Mat(rowNum, colNum)   // create a Matrix to keep the extracted range
      // fill the created matrix with values
    var crow = rowStart  // indexes current row
    var ccol = colStart
    var rowIdx = 0; var colIdx = 0  // indexes at the new Mat
    while  ( crow <= rowEnd )   {
          ccol = colStart;  colIdx = 0
          while  (ccol <= colEnd)   {
                subMatr.sm.set(rowIdx, colIdx, sm.get(crow, ccol))
                colIdx += 1
                ccol += colInc
               }
            rowIdx += 1
            crow += rowInc
       }
     subMatr   // return the submatrix
     }  // positive increment
  else  {  //  negative increment
     var rowNum = Math.floor( (rowEnd-rowStart) / rowInc).asInstanceOf[Int]+1
     var subMatr = new Mat(rowNum, colNum)  // create a Matrix to keep the extracted range
        // fill the created matrix with values
     var  crow = rowStart   // indexes current row at the source matrix
     var  ccol = colStart
     var rowIdx = 0; var colIdx = 0  // indexes at the new Matrix
     while (crow >= rowEnd)  {
         ccol = colStart;  colIdx = 0
         while (ccol <= colEnd)  {
             subMatr.sm.set(rowIdx, colIdx, sm.get(crow, ccol))
             colIdx += 1
             ccol += colInc
         }
         rowIdx += 1
         crow += rowInc
      }
       subMatr  // return the submatrix
     }  // negative increment
}


// extracts a submatrix, e.g. m( ':', 2, 12 ) corresponds to Matlab's m(:, 2:12)'
  def apply(allRowsChar: Char, colLow: Int, colHigh: Int): Mat = {
   var rowStart = 0;     var rowEnd =  Nrows-1   // all rows
    var colStart = colLow;  var colEnd = colHigh
    var rowNum = Nrows-1    // take all the rows

    if (colEnd == -1)  { colEnd = Ncols-1 } // if -1 is specified take all the columns
        
    if  (colStart <= colEnd)   {    // positive increment
        var colNum = colEnd-colStart+1
        var subMatr = new Mat(rowNum, colNum)   // create a Matrix to keep the extracted range
      // fill the created matrix with values
    var crow = rowStart  // indexes current row
    var ccol = colStart  // indexes current column
    var rowIdx = 0; var colIdx = 0  // indexes at the new Matrix

           while  ( crow <= rowEnd )   {
          ccol = colStart;  colIdx = 0
          while  (ccol <= colEnd)   {
                subMatr.sm.set(rowIdx, colIdx, sm.get(crow, ccol))
                colIdx += 1
                ccol += 1
               }
            rowIdx += 1
            crow += 1
     } // crow <= rowEnd
 subMatr
} // positive increment
  else {  // negative increment
    var colNum = colEnd-colStart+1
    var subMatr = new Mat(rowNum, colNum)   // create a Matrix to keep the extracted range
      // fill the created matrix with values
    var crow = rowStart  // indexes current row
    var ccol = colStart  // indexes current column
    var rowIdx = 0; var colIdx = 0  // indexes at the new Matrix

           while  ( crow <= rowEnd )   {
          ccol = colStart;  colIdx = 0
          while  (ccol >= colEnd)   {
                subMatr.sm.set(rowIdx, colIdx, sm.get(crow, ccol))
                colIdx += 1
                ccol += 1
               }
            rowIdx += 1
            crow += 1
     } // crow <= rowEnd
 subMatr   // return the submatrix
    }
   }


  





// extracts a submatrix, e.g. m( ':', 2, 3, 12 ) corresponds to Matlab's m(:, 2:3:12)'
  def apply(allRowsChar: Char, colLow: Int, colInc: Int, colHigh: Int): Mat = {
   var rowStart = 0;     var rowEnd =  Nrows-1   // all rows
    var colStart = colLow;  var colEnd = colHigh
    var rowInc=1
    var rowNum = Nrows-1    // take all the rows

    if (colEnd == -1)  { colEnd = Ncols-1 } // if -1 is specified take all the columns
        
    if  (colStart <= colEnd)   {    // positive increment
        var colNum = Math.floor( (colEnd-colStart) / colInc).asInstanceOf[Int]+1
        var subMatr = new Mat(rowNum, colNum)   // create a Matrix to keep the extracted range
      // fill the created matrix with values
    var crow = rowStart  // indexes current row
    var ccol = colStart  // indexes current column
    var rowIdx = 0; var colIdx = 0  // indexes at the new Matrix

           while  ( crow <= rowEnd )   {
          ccol = colStart;  colIdx = 0
          while  (ccol <= colEnd)   {
                subMatr.sm.set(rowIdx, colIdx, sm.get(crow, ccol))
                colIdx += 1
                ccol += colInc
               }
            rowIdx += 1
            crow += rowInc
     } // crow <= rowEnd
 subMatr
} // positive increment
  else {  // negative increment
    var colNum = Math.floor( (colEnd-colStart) / colInc).asInstanceOf[Int]+1
    var subMatr = new Mat(rowNum, colNum)   // create a Matrix to keep the extracted range
      // fill the created matrix with values
    var crow = rowStart  // indexes current row
    var ccol = colStart  // indexes current column
    var rowIdx = 0; var colIdx = 0  // indexes at the new Matrix

           while  ( crow <= rowEnd )   {
          ccol = colStart;  colIdx = 0
          while  (ccol >= colEnd)   {
                subMatr.sm.set(rowIdx, colIdx, sm.get(crow, ccol))
                colIdx += 1
                ccol += colInc
               }
            rowIdx += 1
            crow += rowInc
     } // crow <= rowEnd
 subMatr   // return the submatrix
   }
   }


// extracts a submatrix, e.g. m( 2, 3, 12, 4, 2,  8 ) corresponds to Matlab's m(2:3:12, 4:2:8)'
  def apply(rowLow: Int, rowInc: Int, rowHigh: Int, colLow: Int, colInc: Int, colHigh: Int): Mat = {
    var rowStart = rowLow;     var rowEnd =  rowHigh
    var colStart = colLow;  var colEnd = colHigh

        var rowNum = Math.floor((rowEnd-rowStart) / rowInc).asInstanceOf[Int]+1
        var colNum = Math.floor( (colEnd-colStart) / colInc).asInstanceOf[Int]+1
        var subMatr = new Mat(rowNum, colNum)   // create a Matrix to keep the extracted range

    if  (rowStart <= rowEnd && colStart <= colEnd)   {    // positive increment at rows and columns
        var crow = rowStart  // indexes current row
        var ccol = colStart  // indexes current column
        var rowIdx = 0; var colIdx = 0  // indexes at the new Matrix
            while  ( crow <= rowEnd )   {
          ccol = colStart;  colIdx = 0
          while  (ccol <= colEnd)   {
                subMatr.sm.set(rowIdx, colIdx, sm.get(crow, ccol))
                colIdx += 1
                ccol += colInc
               }
            rowIdx += 1
            crow += rowInc
     } // crow <= rowEnd
 subMatr
} // positive increment
  else if  (rowStart >= rowEnd && colStart <= colEnd)   {
      // fill the created matrix with values
    var crow = rowStart  // indexes current row
    var ccol = colStart  // indexes current column
    var rowIdx = 0; var colIdx = 0  // indexes at the new Matrix

           while  ( crow >= rowEnd )   {
          ccol = colStart;  colIdx = 0
          while  (ccol <= colEnd)   {
                subMatr.sm.set(rowIdx, colIdx, sm.get(crow, ccol))
                colIdx += 1
                ccol += colInc
               }
            rowIdx += 1
            crow += rowInc
     } // crow <= rowEnd
 subMatr   // return the submatrix
   }
else if  (rowStart <= rowEnd && colStart >= colEnd)   {
      // fill the created matrix with values
    var crow = rowStart  // indexes current row
    var ccol = colStart  // indexes current column
    var rowIdx = 0; var colIdx = 0  // indexes at the new Matrix

           while  ( crow <= rowEnd )   {
          ccol = colStart;  colIdx = 1
          while  (ccol >= colEnd)   {
                subMatr.sm.set(rowIdx, colIdx, sm.get(crow, ccol))
                colIdx += 1
                ccol += colInc
               }
            rowIdx += 1
            crow += rowInc
     } // crow <= rowEnd
 subMatr   // return the submatrix
   }
else {
      // fill the created matrix with values
    var crow = rowStart  // indexes current row
    var ccol = colStart  // indexes current column
    var rowIdx = 0; var colIdx = 0  // indexes at the new Matrix

           while  ( crow >= rowEnd )   {
          ccol = colStart;  colIdx = 0
          while  (ccol >= colEnd)   {
                subMatr.sm.set(rowIdx, colIdx, sm.get(crow, ccol))
                colIdx += 1
                ccol += colInc
               }
            rowIdx += 1
            crow += rowInc
     } // crow > rowEnd
 subMatr   // return the submatrix
   }

   }

// Computes the Kronecker product between this matrix and the provided B matrix:
//      C = kron(A,B)
//     
//     @param B The right matrix in the operation. Not modified.
//     @return Kronecker product between this matrix and B.
def   kron( B: Mat ) = {
        var  C = new DenseMatrix64F(sm.getMatrix.numRows*B.sm.numRows(), sm.getMatrix.numCols*B.sm.numCols())
        CommonOps.kron(sm.getMatrix, B.sm.getMatrix, C)

        new Mat(SimpleMatrix.wrap(C))
    }

}
object Mat  {
// Creates a new SimpleMatrix with random elements drawn from a uniform distribution from minValue to maxValue.
//    @param numRows The number of rows in the new matrix
//    @param numCols The number of columns in the new matrix
//    @param minValue Lower bound
//    @param maxValue Upper bound
//    @param rand The random number generator that's used to fill the matrix.  @return The new random matrix.
def   random(numRows: Int, numCols: Int) = {
        var ret = new Mat(numRows, numCols)
        var r, c=0
        while (r<numRows) {
          c=0
          while (c<numCols) {
             ret(r, c) =  java.lang.Math.random
             c += 1
             }
          r += 1
        }
        ret
}


def ones(numRows: Int, numCols: Int) = {
   var ret = new Mat(numRows, numCols)
    var r, c=0
        while (r<numRows) {
          c=0
          while (c<numCols) {
             ret(r, c) =  1.0
             c += 1
             }
          r += 1
        }
        ret
 }


def zeros(numRows: Int, numCols: Int) = {
   var ret = new Mat(numRows, numCols)
    var r, c=0
        while (r<numRows) {
          c=0
          while (c<numCols) {
             ret(r, c) =  0.0
             c += 1
             }
          r += 1
        }
        ret
 }


def fill(numRows: Int, numCols: Int, value: Double) = {
   println(" filling matrix with numRows = "+numRows+" numCols = "+numCols+" with value = "+value)
   var ret = new Mat(numRows, numCols)
    var r, c=0
        while (r<numRows) {
          c=0
          while (c<numCols) {
             ret(r, c) =  value
             c += 1
             }
          r += 1
        }
        ret
 }


def sin(m: Mat) = {
   var numRows = m.Nrows
   var numCols = m.Ncols
   var ret = new Mat(numRows, numCols) 
   var r, c=0
   while (r<numRows) {
     c=0
          while (c<numCols) {
             ret(r, c) =  Math.sin(m(r,c))
             c += 1
             }
          r += 1
        }
        ret
 }


  
def cos(m: Mat) = {
   var numRows = m.Nrows
   var numCols = m.Ncols
   var ret = new Mat(numRows, numCols) 
   var r, c=0
   while (r<numRows) {
     c=0
          while (c<numCols) {
             ret(r, c) =  Math.cos(m(r,c))
             c += 1
             }
          r += 1
        }
        ret
 }


def tan(m: Mat) = {
   var numRows = m.Nrows
   var numCols = m.Ncols
   var ret = new Mat(numRows, numCols) 
   var r, c=0
   while (r<numRows) {
     c=0
          while (c<numCols) {
             ret(r, c) =  Math.tan(m(r,c))
             c += 1
             }
          r += 1
        }
        ret
 }


def acos(m: Mat) = {
   var numRows = m.Nrows
   var numCols = m.Ncols
   var ret = new Mat(numRows, numCols) 
   var r, c=0
   while (r<numRows) {
     c=0
          while (c<numCols) {
             ret(r, c) =  Math.acos(m(r,c))
             c += 1
             }
          r += 1
        }
        ret
 }



def asin(m: Mat) = {
   var numRows = m.Nrows
   var numCols = m.Ncols
   var ret = new Mat(numRows, numCols) 
   var r, c=0
   while (r<numRows) {
     c=0
          while (c<numCols) {
             ret(r, c) =  Math.asin(m(r,c))
             c += 1
             }
          r += 1
        }
        ret
 }


def atan(m: Mat) = {
   var numRows = m.Nrows
   var numCols = m.Ncols
   var ret = new Mat(numRows, numCols) 
   var r, c=0
   while (r<numRows) {
     c=0
          while (c<numCols) {
             ret(r, c) =  Math.atan(m(r,c))
             c += 1
             }
          r += 1
        }
        ret
 }




def cosh(m: Mat) = {
   var numRows = m.Nrows
   var numCols = m.Ncols
   var ret = new Mat(numRows, numCols) 
   var r, c=0
   while (r<numRows) {
     c=0
          while (c<numCols) {
             ret(r, c) =  java.lang.Math.cosh(m(r,c))
             c += 1
             }
          r += 1
        }
        ret
 }



def sinh(m: Mat) = {
   var numRows = m.Nrows
   var numCols = m.Ncols
   var ret = new Mat(numRows, numCols) 
   var r, c=0
   while (r<numRows) {
     c=0
          while (c<numCols) {
             ret(r, c) =  java.lang.Math.sinh(m(r,c))
             c += 1
             }
          r += 1
        }
        ret
 }


def tanh(m: Mat) = {
   var numRows = m.Nrows
   var numCols = m.Ncols
   var ret = new Mat(numRows, numCols) 
   var r, c=0
   while (r<numRows) {
     c=0
          while (c<numCols) {
             ret(r, c) =  java.lang.Math.tanh(m(r,c))
             c += 1
             }
          r += 1
        }
        ret
 }


// Computes a full Singular Value Decomposition (SVD) of this matrix with the
//  eigenvalues ordered from largest to smallest.
//   @return SVD
def svd(m: Mat) = {
      m.sm.svd()
    }

//  Creates a matrix where all but the diagonal elements are zero.  The values
//  of the diagonal elements are specified by the parameter 'vals'.
//     @param vals The values of the diagonal elements.
//      @return A diagonal matrix.
def  diag( vals: Seq[Double] ) = {
        new Mat( SimpleMatrix.diag( vals:_* ))
    }



//  Computes the SVD in either  compact format or full format.
//  @return SVD of this matrix.
def  svd(m:Mat, compact: Boolean ) = {
      m.sm.svd(compact)
    }



 //  Returns the Eigen Value Decomposition (EVD) of this matrix.
def eig(m: Mat) = {
  m.sm.eig()
  }

// convert from EJMLMat to Matrix
def toMatrix(m: Mat) = {
  var dataArray = m.getv   // get the data array
  var matrix = new scalaSci.Matrix(dataArray)
  matrix
}

// convert from Matrix to EJMLMat to 
def toEJMLMat(m: scalaSci.Matrix) = {
  var dataArray = m.getv   // get the data array
  var sm = new org.ejml.simple.SimpleMatrix(dataArray)
  var EJMLmat = new Mat(sm)
  EJMLmat
 }

def  transpose(m: scalaSci.EJML.Mat)  = {
   m.transpose
   }

def det(m: scalaSci.EJML.Mat) = 
   m.det
   

// construct a Matrix from a String 
// var m = M("3.4 -6.7; -1.2 5.6")
def M(s: String) =  {
    var nRows = 1
    var nCols = 0
    for (i<-0 to s.length-1)   // count how many rows are specified
      if  (s(i)==';')
        nRows += 1

  // seperate rows to an ArrayBuffer
   var buf = new scala.collection.mutable.ArrayBuffer[String]()
   var strtok = new java.util.StringTokenizer(s, ";")  // rows are separated by ';'
   while (strtok.hasMoreTokens) {
         val tok = strtok.nextToken
         buf +=tok
      }    

// count how many numbers each row has. Assuming that each line has the same number of elements
 val firstLine = buf(0)
 strtok = new java.util.StringTokenizer(firstLine, ", ")  // elements are separated by ',' or ' '
 while (strtok.hasMoreTokens) {
   val tok = strtok.nextToken
   nCols += 1  
}

// allocate double array
var elems = new Array[Array[Double]](nRows, nCols)
  // pass elements from ArrayBuffer to double array
for (k <- 0 to buf.length-1)  {  // read array
   var currentLine = buf(k)
   strtok = new java.util.StringTokenizer(currentLine, ", ")  // elements are separated by ',' or ' '
var c=0 
while (strtok.hasMoreTokens) {  // read row
   val tok = strtok.nextToken
   var cNumber = tok.toDouble
   elems(k)(c) = cNumber
   c += 1
     }   // read row
   }  // read array

 // return the converted EJML Mat
 new Mat(elems)
 }  

def inv(m: Mat) = {
 new Mat( m.sm.invert)
   }


def testMat(N: Int, M: Int) = {
  var a = new Mat(N, M)
  for (rows <- 0 until N)
    for (cols <-0 until M)
      a(rows, cols) = rows*10+cols

  a
}
}
